﻿using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using MongoDB.Bson;
using System.Text.RegularExpressions;
using MongoDB.Driver.Core;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Benlai.Mongo;
using Benlai.Util;

namespace Benlai.Dac.Mongo
{
    public class MongoHandler<T> where T : MongoModel
    {
        private static string connection = ConfigUtil.GetAppSetting("MongoDB");

        private string dbName = "local";
        /// <summary>
        /// 数据库名称，默认空为local
        /// </summary>
        public string DBName
        {
            set { dbName = value; }
        }

        private string name = "test";
        /// <summary>
        /// 集合名
        /// </summary>
        public string Name
        {
            set { name = value; }
        }

        /// <summary>
        /// 排序字段
        /// </summary>
        public string SortPropertyName { get; set; }

        /// <summary>
        /// 排序升降
        /// </summary>
        public bool IsDescending { get; set; }

        #region AAA

        /// <summary>
        /// 根据数据库配置信息创建MongoDatabase对象，如果不指定配置信息，则从默认信息创建
        /// </summary>
        /// <param name="databaseName">数据库名称，默认空为local</param>
        /// <returns></returns>
        private IMongoDatabase CreateDatabase()
        {
            string connectionString = connection;
            if (string.IsNullOrWhiteSpace(connectionString))
                throw new ArgumentNullException("MongoDB连接字符串为空");

            try
            {
                var client = new MongoClient(connectionString);

                return client.GetDatabase(dbName);
            }
            catch (Exception ex)
            {
                ErrorLog.GetInstance().Write("链接MongoDB数据库报错：" + ex);
            }
            return null;
        }

        /// <summary>
        /// 获取操作对象的MongoCollection集合,强类型对象集合
        /// </summary>
        /// <returns></returns>
        protected virtual IMongoCollection<T> GetCollection()
        {
            IMongoDatabase database = CreateDatabase();
            return database.GetCollection<T>(name);
        }

        /// <summary>
        /// 查询数据库,检查是否存在指定ID的对象
        /// </summary>
        /// <param name="key">对象的ID值</param>
        /// <returns>存在则返回指定的对象,否则返回Null</returns>
        public virtual T FindByID(string id)
        {
            if (string.IsNullOrWhiteSpace(id))
                throw new Exception(string.Format("传入的对象id为空,id={0}", id));

            IMongoCollection<T> collection = GetCollection();
            return collection.Find(s => s.Id == id).FirstOrDefault();
        }

        /// <summary>
        /// 根据条件查询数据库,如果存在返回第一个对象
        /// </summary>
        /// <param name="filter">条件表达式</param>
        /// <returns>存在则返回指定的第一个对象,否则返回默认值</returns>
        protected virtual T FindSingle(FilterDefinition<T> filter)
        {
            IMongoCollection<T> collection = GetCollection();
            return collection.Find(filter).FirstOrDefault();
        }

        /// <summary>
        /// 根据条件查询数据库,并返回对象集合
        /// </summary>
        /// <param name="match">条件表达式</param>
        /// <returns>指定对象的集合</returns>
        protected virtual IList<T> Find(FilterDefinition<T> query)
        {
            return GetQueryable(query).ToList();
        }
        
        /// <summary>
        /// 返回可查询的记录源
        /// </summary>
        /// <param name="query">查询条件</param>
        /// <returns></returns>
        protected virtual IFindFluent<T, T> GetQueryable(FilterDefinition<T> query)
        {
            return GetQueryable(query, this.SortPropertyName, this.IsDescending);
        }

        /// <summary>
        /// 根据条件表达式返回可查询的记录源
        /// </summary>
        /// <param name="query">查询条件</param>
        /// <param name="sortPropertyName">排序表达式</param>
        /// <param name="isDescending">如果为true则为降序，否则为升序</param>
        /// <returns></returns>
        protected virtual IFindFluent<T, T> GetQueryable(FilterDefinition<T> query, string sortPropertyName, bool isDescending = true)
        {
            IMongoCollection<T> collection = GetCollection();
            IFindFluent<T, T> queryable = collection.Find(query);

            var sort = isDescending ? Builders<T>.Sort.Descending(sortPropertyName) : Builders<T>.Sort.Ascending(sortPropertyName);
            return queryable.Sort(sort);
        }

        /// <summary>
        /// 根据条件查询数据库,并返回对象集合(用于分页数据显示)
        /// </summary>
        /// <param name="query">条件表达式</param>
        /// <param name="info">分页实体</param>
        /// <returns>指定对象的集合</returns>
        protected virtual IEnumerable<T> FindWithPager(FilterDefinition<T> query, int pageIndex, int pageSize, out int recordCount)
        {
            recordCount = 0;
            return FindWithPager(query, pageIndex, pageSize, out recordCount, this.SortPropertyName, this.IsDescending);
        }

        /// <summary>
        /// 根据条件查询数据库,并返回对象集合(用于分页数据显示)
        /// </summary>
        /// <param name="query">条件表达式</param>
        /// <param name="info">分页实体</param>
        /// <returns>指定对象的集合</returns>
        protected virtual IEnumerable<T> FindWithPager(FilterDefinition<T> query, int pageIndex, int pageSize, out int recordCount, string sortPropertyName, bool isDescending = true)
        {
            int excludedRows = (pageIndex - 1) * pageSize;
            var find = GetQueryable(query, sortPropertyName, isDescending);
            recordCount = (int)find.Count();
            return find.Skip(excludedRows).Limit(pageSize).ToEnumerable();
        }

        /// <summary>
        /// 插入指定对象到数据库中
        /// </summary>
        /// <param name="t">指定的对象</param>
        /// <returns>执行成功返回<c>true</c>，否则为<c>false</c></returns>
        public virtual void Insert(T t)
        {
            if (t == null)
                throw new Exception("传入的对象t为空");

            IMongoCollection<T> collection = GetCollection();
            collection.InsertOne(t);
        }

        /// <summary>
        /// 插入指定对象集合到数据库中
        /// </summary>
        /// <param name="list">指定的对象集合</param>
        /// <returns>执行成功返回<c>true</c>，否则为<c>false</c></returns>
        public virtual void InsertBatch(IEnumerable<T> list)
        {
            if (list == null || list.Count() <= 0)
                throw new Exception("传入的对象t为空");

            IMongoCollection<T> collection = GetCollection();
            collection.InsertMany(list); //部分成功也返回true
        }

        /// <summary>
        /// 更新对象属性到数据库中
        /// </summary>
        /// <param name="t">指定的对象</param>
        /// <param name="id">主键的值</param>
        /// <returns>执行成功返回<c>true</c>，否则为<c>false</c></returns>
        public virtual bool Update(T t, string id)
        {
            if (t == null)
                throw new Exception("传入的对象t为空");
            if (string.IsNullOrWhiteSpace(id))
                throw new Exception(string.Format("传入的对象id为空,id={0}", id));

            bool result = false;
            IMongoCollection<T> collection = GetCollection();
            //使用 IsUpsert = true ，如果没有记录则写入
            var update = collection.ReplaceOne(s => s.Id == id, t, new UpdateOptions() { IsUpsert = true });
            result = update != null && update.MatchedCount > 0;

            return result;
        }

        /// <summary>
        /// 封装处理更新的操作(部分字段更新)
        /// </summary>
        /// <param name="id">主键的值</param>
        /// <param name="update">更新对象</param>
        /// <returns>执行成功返回<c>true</c>，否则为<c>false</c></returns>
        public virtual bool Update(string id, UpdateDefinition<T> update)
        {
            if (update == null)
                throw new Exception("传入的对象update为空");
            if (string.IsNullOrWhiteSpace(id))
                throw new Exception(string.Format("传入的对象id为空,id={0}", id));

            IMongoCollection<T> collection = GetCollection();
            var result = collection.UpdateOne(s => s.Id == id, update, new UpdateOptions() { IsUpsert = true });
            return result != null && result.ModifiedCount > 0;
        }

        /// <summary>
        /// 根据指定对象的ID,从数据库中删除指定对象
        /// </summary>
        /// <param name="id">对象的ID</param>
        /// <returns>执行成功返回<c>true</c>，否则为<c>false</c>。</returns>
        public virtual bool Delete(string id)
        {
            if (string.IsNullOrWhiteSpace(id))
                throw new Exception(string.Format("传入的对象id为空,id={0}", id));

            IMongoCollection<T> collection = GetCollection();
            var result = collection.DeleteOne(s => s.Id == id);
            return result != null && result.DeletedCount > 0;
        }

        /// <summary>
        /// 根据指定对象的ID,从数据库中删除指定指定的对象
        /// </summary>
        /// <param name="idList">对象的ID集合</param>
        /// <returns>执行成功返回<c>true</c>，否则为<c>false</c>。</returns>
        public virtual bool DeleteBatch(List<string> idList)
        {
            if (idList == null)
                throw new Exception("传入的对象idList为空");

            IMongoCollection<T> collection = GetCollection();

            var result = collection.DeleteMany(s => idList.Contains(s.Id));
            return result != null && result.DeletedCount > 0;
        }

        
        #endregion




        public IEnumerable<T> GetModel<U>(U template)
        {
            return GetQueryable(GeneratorMongoQuery(template)).ToEnumerable<T>();
        }

        public IEnumerable<T> GetModel<U>(U template, string sortPropertyName, bool isDescending = true)
        {
            return GetQueryable(GeneratorMongoQuery(template), sortPropertyName, isDescending).ToEnumerable<T>();
        }

        public IEnumerable<T> GetModel(int pageIndex, int pageSize, out int recordCount)
        {
            return GetModel(new { }, pageIndex, pageSize, out recordCount);
        }

        public IEnumerable<T> GetModel<U>(U template, int pageIndex, int pageSize, out int recordCount)
        {
            return FindWithPager(GeneratorMongoQuery(template), pageIndex, pageSize, out recordCount);
        }

        public IEnumerable<T> GetModel<U>(U template, int pageIndex, int pageSize, out int recordCount, string sortPropertyName, bool isDescending = true)
        {
            return FindWithPager(GeneratorMongoQuery(template), pageIndex, pageSize, out recordCount, sortPropertyName, isDescending);
        }

        /// <summary>
        /// 构建Mongo的查询表达式，通过一个匿名对象
        /// </summary>
        /// <typeparam name="U"></typeparam>
        /// <param name="template"></param>
        /// <returns></returns>
        private BsonDocumentFilterDefinition<T> GeneratorMongoQuery<U>(U template)
        {
            var qType = typeof(U);
            var outter = new BsonDocument();
            var simpleQuery = new BsonDocument();
            foreach (var item in qType.GetProperties())
            {
                if (item.PropertyType.IsClass && item.PropertyType != typeof(string))
                {
                    //复杂类型，导航属性，类对象和集合对象 
                    foreach (var sub in item.PropertyType.GetProperties())
                    {
                        simpleQuery.Add(new BsonElement(item.Name + "." + sub.Name, BsonValue.Create(sub.GetValue(item.GetValue(template)))));
                    }
                }
                else
                {
                    //简单类型,ValueType和string
                    simpleQuery.Add(new BsonElement(item.Name,
                      BsonValue.Create(item.GetValue(template))
                        ));
                }
            }
            return new BsonDocumentFilterDefinition<T>(simpleQuery);
        }
    }
}